# GPL 3 or later

import os
import json
import time
import random
import threading
import subprocess
from datetime import datetime
from datetime import timedelta
from ui import *

now = {"now_playing":None,
       "mpv": None}


# There will be 2 threads. One showing the current progress. The other playing the actual
# songs themselves.

def get_list():

    with open('stuff.json') as json_file: 
        stuff = json.load(json_file)

    new_date_format = "%Y/%m/%d"
    today = datetime.strftime(datetime.today(), new_date_format)
        
    playlist = []

    users_songs = {}
    
    for n, username in enumerate(stuff.get("users", {})):
        if username in stuff.get("present", {}).get(today, []):
            user = stuff.get("users", {}).get(username, {})
            users_songs[username] = user.get("now", []).copy()

    while users_songs:
        try:
            for user in users_songs:
                if not users_songs[user]:
                    try:
                        del users_songs[user]
                    except:
                        pass
                else:
                    videoId = users_songs[user].pop(0)
                    playlist.append({"username":user,
                                     "videoId":videoId,
                                     "data":stuff.get("songs", {}).get(videoId, {})})
        except:
            pass
    return playlist
        

def player():

    index = 0
    
    while True:
        index = index + 1
        try:
            
            
            
            
            
            time.sleep(5)

            if datetime.now().hour >= 16 and datetime.now().minute >= 50:
                os.system("shutdown --poweroff")
                # Instead of turning it off we wait till the morning
                # which is 14 hours
                #time.sleep(60*60*14)
                break
            
            with open('stuff.json') as json_file: 
                stuff = json.load(json_file)

            # Checking if it's time to play songs.
            tobreak = False
            for br in stuff.get("breaks", []):
                if br.get("start", {}).get("hour", 0) <= datetime.now().hour\
                   and br.get("start", {}).get("minute", 0) <= datetime.now().minute\
                   and br.get("end", {}).get("hour", 0) >= datetime.now().hour\
                   and br.get("end", {}).get("minute", 0) >= datetime.now().minute:

                    tobreak = True
            if tobreak:
                continue

            # Pipewire eats a lot of RAM. So to avoid it, before
            # each song we restart it.
            if index % 5 == 0:
                os.system("systemctl --user restart pipewire.service")
                time.sleep(10)
                

            playlist = get_list()

            # Checks!

            users = []
            for i in playlist:
                if i["username"] not in users:
                    users.append(i["username"])

            # If only the music operator sent songs. We wait for more people to send
            # songs.
            # if len(users) == 1 and stuff.get("matrix", {}).get("username") in users:
            #     continue

            # If there not a single song by the operator. Add one random from his
            # history.

            # for user in stuff.get("users", {}):
            #     if not stuff.get("users", {}).get(user, {}).get("now", [])\
            #        and len(stuff.get("users", {}).get(user, {}).get("history", [])) > 4:
            

            #         try:
            #             rs = random.choice(stuff["users"][user]["history"])
            #             stuff["users"][user]["now"].append(rs)

            #             with open('stuff.json', 'w') as fp:
            #                 json.dump(stuff, fp, indent=4)
            #         except:
            #             pass


            for i in playlist:
                filename = i["data"].get("file")
                username = i["username"]
                videoId  = i["videoId"]
                if filename:# and (time.time() - stuff.get("songs", {}).get(videoId, {}).get("last_played", 0)) > 60*60*2:

                    # Writing the time at which the song started playing

                    with open('stuff.json') as json_file: 
                        stuff = json.load(json_file)

                    stuff["last_played"] = int(time.time())
                    stuff["now_playing"] = videoId
                    stuff["now_username"] = username

                    with open('stuff.json', 'w') as fp:
                         json.dump(stuff, fp, indent=4)

                    # Playing the song

                    now["now_playing"] = videoId
                    now["mpv"] = subprocess.Popen(["mpv", filename, "--no-video", "--audio-channels=mono", "--af=lavfi=dynaudnorm", "--no-terminal"])
                    now["mpv"].wait()

                    # Removing the song from the 'now' playlist

                    with open('stuff.json') as json_file: 
                        stuff = json.load(json_file)

                    try:
                        
                        stuff["songs"][videoId]["last_played"] = int(time.time())
                        while videoId in stuff["users"][username]["now"]:
                            stuff["users"][username]["now"].remove(videoId)
                        user = stuff["users"][username].copy()
                        del stuff["users"][username]
                        stuff["users"][username] = user

                    except:
                        pass

                    with open('stuff.json', 'w') as fp:
                         json.dump(stuff, fp, indent=4)
                    # In case
                    if stuff and "songs" in stuff and "users" in stuff:
                        with open('stuff_backup.json', 'w') as fp:
                            json.dump(stuff, fp, indent=4)
                    break

                # elif not (time.time() - stuff.get("songs", {}).get(videoId, {}).get("last_played", 0)) > 60*60*2:

                #     with open('stuff.json') as json_file: 
                #         stuff = json.load(json_file)
                    
                #     try:
                #         while videoId in stuff["users"][username]["now"]:
                #             stuff["users"][username]["now"].remove(videoId)
                #     except:
                #         pass

                #     with open('stuff.json', 'w') as fp:
                #          json.dump(stuff, fp, indent=4)

            
        except:
            pass
            
t2 = threading.Thread(target=player)
t2.setDaemon(True)
t2.start()


while True:

    

    
    try:
        time.sleep(1)

        with open('stuff.json') as json_file: 
            stuff = json.load(json_file)

        new_date_format = "%Y/%m/%d"
        today = datetime.strftime(datetime.today(), new_date_format)
        for d in range(400):
            yesterday = datetime.strftime(datetime.today()-timedelta(days=d+1), new_date_format)
            if yesterday in stuff.get("volume", {}):
                break
    
        
        # Making volume 20%
        try:
            v = stuff["volume"][yesterday]["average"]
        except:
            v = 20
        try:
            v = stuff["volume"][today]["average"]
        except:
            pass
        y = 0
        try:
            y = stuff["volume"][yesterday]["average"]
        except:
            pass
        
        os.system("amixer -D pulse sset Master "+str(max(0,min(v, 100))*0.3)+"%")
        os.system("clear")

        users_volumes = {}
        try:
            users_volumes = stuff["volume"][today]["users"]
        except:
            pass

        w, h = tsize()
        w = w - 4
        h = h - 5

        playlist = get_list()
        print()
        for n, i in enumerate(playlist):
            if n > h-len(stuff.get("present", {}).get(today, []))-5:
                break

            if now["now_playing"] == i["videoId"]:
                playing = clr["bdbu"]+" >  "
            elif i["data"].get("file"):
                playing = "    "
            else:
                playing = clr["bdyl"]+"..."+clr["norm"]+" "

            print("  "+playing+clr["bold"]+wdth(i["data"].get("title"), w-40)+clr["norm"]+"  "+\
                  clr["tdbl"]+"t"+clr["tbyl"]+wdth(timestring(i["data"].get("duration")), 10)+clr["norm"]+"  "+\
                  wdth(user_emoji(i["username"],stuff), 19, False))


        # Percent of the song ( Progress bar in the bottom
        duration = stuff.get("songs", {}).get(now["now_playing"], {}).get("duration", 1)
        started = stuff.get("last_played", 0)
        percent = max(0, min(1, (time.time()-started) / duration))

        

            
        print()
        print("  "+wdth(timestring(duration)+" / "+timestring(int(time.time()-started)), int(w/5))+clr["bbbu"]+(" "*int((w-int(w/5))*percent))+clr["norm"])
        print()

        # VOLUME
        
        us = []
        for u in stuff.get("present", {}).get(today, []):
            
            try:
                print( "        ", wdth(user_emoji(u, stuff), int(w/3), False), clr["tdbl"]+"t"+clr["norm"], clr["tbyl"], str(round(users_volumes[u], 2))+"%" , clr["norm"])
                us.append(u)
            except:
                print( "        ", wdth(user_emoji(u, stuff), int(w/3), False), clr["tdbl"]+"t"+clr["norm"], clr["tbrd"], "Not Voted!" , clr["norm"])
        print()
        not_voted = 0
        for u in stuff.get("present", {}).get(today, []):
            if u not in us:
                not_voted = not_voted+1

        if not_voted:
            center("      + ( "+ str(not_voted)+ " * " + str(round(y,2))+"% )  not voted! ", "tbrd")
            print()

        if stuff.get("skip"):
            try:
                now["mpv"].kill()
                stuff["skip"] = False
                videoId = stuff["now_playing"]
                username = stuff["now_username"]
                stuff["songs"][videoId]["last_played"] = int(time.time())
                while videoId in stuff["users"][username]["now"]:
                    stuff["users"][username]["now"].remove(videoId)
                    user = stuff["users"][username].copy()
                    del stuff["users"][username]
                    stuff["users"][username] = user

            except:
                pass

            with open('stuff.json', 'w') as fp:
                json.dump(stuff, fp, indent=4)

        print("  "+wdth("Volume: "+str(round(v, 2))+"%", int(w/5))+clr["bbbu"]+(" "*int((w-int(w/5))*(v/100)))+clr["norm"])


        
    except Exception as e:
        pass
